package com.olympus.hermes.common.advice;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.olympus.hermes.common.annotation.IgnoreResponseAdvice;
import com.olympus.hermes.common.bean.Result;
import org.springframework.boot.autoconfigure.condition.ConditionalOnClass;
import org.springframework.core.MethodParameter;
import org.springframework.data.domain.Page;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.server.ServerHttpRequest;
import org.springframework.http.server.ServerHttpResponse;
import org.springframework.lang.NonNull;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.servlet.mvc.method.annotation.ResponseBodyAdvice;

import java.util.Objects;


/**
 * @author Mickey
 * @since 2021/1/21
 */
@RestControllerAdvice
@ConditionalOnClass(ResponseBodyAdvice.class)
public class CommonResponseDataAdvice implements ResponseBodyAdvice<Object> {

    private final ObjectMapper objectMapper;

    public CommonResponseDataAdvice(ObjectMapper objectMapper) {
        this.objectMapper = objectMapper;
    }

    @Override
    public boolean supports(MethodParameter methodParameter, @NonNull Class<? extends HttpMessageConverter<?>> converterType) {
        if (methodParameter.getDeclaringClass().isAnnotationPresent(IgnoreResponseAdvice.class)) {
            return false;
        }
        return !Objects.requireNonNull(methodParameter.getMethod()).isAnnotationPresent(IgnoreResponseAdvice.class);
    }

    @Override
    public Object beforeBodyWrite(Object body,
                                  @NonNull MethodParameter returnType,
                                  @NonNull MediaType selectedContentType,
                                  @NonNull Class<? extends HttpMessageConverter<?>> selectedConverterType,
                                  ServerHttpRequest request,
                                  @NonNull ServerHttpResponse response) {

        if (Objects.isNull(body)) {
            return Result
                    .builder()
                    .status(HttpStatus.OK.value())
                    .build();
        }

        if (body instanceof String) {
            try {
                return objectMapper.writeValueAsString(Result
                        .builder()
                        .status(HttpStatus.OK.value())
                        .data(body)
                        .build());
            } catch (JsonProcessingException e) {
                e.printStackTrace();
            }
        }

        if (body instanceof Result) {
            return body;
        }

        if (body.getClass().getName().equals("org.springframework.data.domain.PageImpl")) {
            Page page = (Page) body;
            return Result
                    .builder()
                    .data(page.getContent())
                    .status(HttpStatus.OK.value())
                    .page(page.getNumber())
                    .total(page.getTotalElements())
                    .build();
        }

        return Result
                .builder()
                .data(body)
                .status(HttpStatus.OK.value())
                .build();
    }
}
